#pragma once
#include <string>
#include <list>
#include <set>
#include <stack>
#include <algorithm>
#include <xscript/xerror.h>
#include <xscript/xtoken.h>
#include <xscript/xscriptexecutor.h>

class XLexParser {
    static std::set<wchar_t> separator;
    static std::set<std::wstring> keywords;
    static std::set<std::wstring> booleans;
    static std::set<std::wstring> symbols;
    static std::set<std::wstring> enterBlockKeywords;
    static std::set<std::wstring> exitBlockKeywords;
    static std::set<std::wstring> enterExitBlockKeywords;
    static std::wstring multiCommentFlag;
    static std::wstring numberRegex;
  public:
    XLexParser();
  public:
    void setModuleName(const std::wstring& module);
    bool parse(const std::wstring& input, uint32_t line);
    XTokenBlock getTokens()const {return tokenBlock;}
  private:
    template<class C, class K>
    inline bool contain(const C& container, const K& k) {
        return std::find(container.begin(), container.end(), k) != container.end();
    }

    bool isInteger(const std::wstring& string);
    bool makeToken(const std::vector<std::wstring>& words, uint32_t line);
    bool isValidVariableName(const std::wstring& word);

    bool doKeyword(const std::wstring& keyword, uint32_t line);

    bool needEnterBlock(const std::wstring& keyword);
    bool needExitBlock(const std::wstring& keyword);
    bool needExitAndEnterBlock(const std::wstring& keyword);

    void addToken(std::shared_ptr<XToken>token, uint32_t line);
  private:
    bool isMultiComment = false;
    std::wstring currentModule;
    XTokenBlock tokenBlock;
    std::stack<uint32_t> blocks;
};
